﻿using System;
using SharedIFaces;
using System.Data.SqlClient;
using System.Data;
using Data;
using System.IO;

namespace ConsoleServer
{
    public class WCF_Server : IServer
    {
        private readonly String _connStr = @"Data Source=.\SQLExpress;" +
                                            @"Initial Catalog=demoplayerdotnet;" +
                                            @"Integrated Security=True;";
        public String ConnStr
        {
            get { return _connStr; }
            //set { _connStr = value; }
        }

        private SqlConnection _connection;
        public SqlConnection Connection
        {
            get
            {
                // проверяем, есть ли екземпляр _сonnection
                // если нет - создаем
                if (null == _connection)
                {
                    _connection = new SqlConnection(ConnStr);
                }
                // проверка на наличие сломанного соединения
                // если нет - закрываем
                if (ConnectionState.Broken == _connection.State)
                {
                    _connection.Close();
                }
                // если соединение есть, но закрыто - открываем его
                if (ConnectionState.Closed == _connection.State)
                {
                    try
                    {
                        _connection.Open();
                        //MessageBox.Show("DB Connected successfully");
                    }
                    catch (SqlException ex)
                    {
                        //MessageBox.Show("DB Connection Error");
                        return null;
                    }
                }
                return _connection;
            }
        }

        #region Члены IServer

        User IServer.CreateUser(String login, String password)
        {
            SqlCommand command = Connection.CreateCommand();
            command.CommandText = "SELECT [id], [passwd], [admin] FROM " + User.TableName +
                                  " WHERE [id] = '" + login + "' AND [passwd] = '" + password + "'";

            using (SqlDataReader reader = command.ExecuteReader())
            {
                if (reader.HasRows)
                {
                    User us = new User(reader);
                    Console.WriteLine("User [" + us.Name + "] entered");
                    return us;
                }
                else
                {
                    Console.WriteLine("Bad Authorization");
                    return null;
                }
            }

        }

        String IServer.GetTable(String table_name)
        {
            Console.WriteLine("REQUEST FROM CLIENT: Get table " + table_name);

            String query = "SELECT * FROM " + table_name;

            // Connect to the database and run the query.        
            SqlDataAdapter adapter = new SqlDataAdapter(query, Connection);

            DataSet tmp_ds = new DataSet("ds_" + table_name);
            DataTable tmp_dt = new DataTable(table_name);
            // Fill the DataTable.
            adapter.Fill(tmp_dt);
            
            tmp_ds.Tables.Add(tmp_dt);

            Console.WriteLine("Table " + table_name + " sent");
            string tmp = tmp_ds.GetXml();
            return tmp;
        }
        
        void IServer.UpdateTable(String table_name, String content)
        {
            // выводим в консоль имя таблицы, которую будем обновлять
            Console.WriteLine("REQUEST FROM CLIENT: Update of table " + table_name);

            System.IO.StringReader content_xml = new System.IO.StringReader(content);

            DataSet tmp_ds = new DataSet("ds_" + table_name);
            tmp_ds.ReadXml(content_xml, XmlReadMode.Auto);

            // изменяем RowState строки в таблице на Modified
            tmp_ds.AcceptChanges();
            tmp_ds.Tables[table_name].Rows[0].SetModified();
            
            String query = "SELECT * FROM " + table_name;
            
            // Connect to the database and run the query.        
            SqlDataAdapter adapter = new SqlDataAdapter(query, Connection);

            // Create a command builder to generate SQL update, insert, and
            // delete commands based on selectCommand. These are used to
            // update the database.
            SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter);

            String Update_Text = @"UPDATE " + table_name + " SET";
            SqlCommand cmd = new SqlCommand(Update_Text, Connection);

            // здесь нужно задать все параметры для команды UPDATE
            foreach (var column in tmp_ds.Tables[table_name].Columns)
            {
                String column_name = ((DataColumn)column).ColumnName;
                if ("id" != column_name)
                {
                    Update_Text += " [" + column_name + "] = @" + column_name + ",";

                    // добавляем параметры в команду UPDATE
                    // (выставляем соответствие столбцам принятой таблицы)
                    //cmd.Parameters.Add("@" + column_name,  SqlDbType.NVarChar, 50, column_name);

                    // попытка обойти задание типа SqlDbType
                    // похоже, что работает
                    SqlParameter p = new SqlParameter();
                    p.ParameterName = "@" + column_name;
                    p.SourceColumn = column_name;
                    cmd.Parameters.Add(p);
                }
            }

            // удаляем последнюю запятую в тексте команды
            Update_Text = Update_Text.Remove(Update_Text.Length - 1);
            // добавляем условие
            Update_Text += " WHERE [id] = @id";
            // задаем первичный ключ
            SqlParameter parm = cmd.Parameters.Add("@id", SqlDbType.VarChar, 50, "id");
            parm.SourceVersion = DataRowVersion.Original;            

            // окончательно выставляем текст команды обновления
            cmd.CommandText = Update_Text;

            // передаем ее адаптеру
            adapter.UpdateCommand = cmd;

            // и, наконец-то, пытаемся обновить таблицу
            adapter.Update(tmp_ds, table_name);
            
            Console.WriteLine("Updated table " + table_name);
        }

        void IServer.InsertToTable(String table_name, String content)
        {
            // выводим в консоль имя таблицы, которую будем обновлять
            Console.WriteLine("REQUEST FROM CLIENT: Insert to table " + table_name);

            System.IO.StringReader content_xml = new System.IO.StringReader(content);

            DataSet tmp_ds = new DataSet("ds_" + table_name);
            tmp_ds.ReadXml(content_xml, XmlReadMode.Auto);

            String query = "SELECT * FROM " + table_name;

            // Connect to the database and run the query.        
            SqlDataAdapter adapter = new SqlDataAdapter(query, Connection);

            // Create a command builder to generate SQL update, insert, and
            // delete commands based on selectCommand. These are used to
            // update the database.
            SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter);
            //SqlCommand c = commandBuilder.GetUpdateCommand();

            String Insert_Text = @"INSERT INTO " + table_name;
            SqlCommand cmd = new SqlCommand(Insert_Text, Connection);

            String insertion_columns = "(";
            String insertion_parameters = " VALUES (";

            // здесь нужно задать все параметры для команды UPDATE
            foreach (var column in tmp_ds.Tables[table_name].Columns)
            {
                String column_name = ((DataColumn)column).ColumnName;

                insertion_columns += column_name + ", ";
                insertion_parameters += "@" + column_name + ", ";

                // добавляем параметры в команду UPDATE
                // (выставляем соответствие столбцам принятой таблицы)
                //cmd.Parameters.Add("@" + column_name, SqlDbType.NVarChar, 50, column_name);

                // попытка обойти задание типа SqlDbType
                // похоже, что работает
                SqlParameter p = new SqlParameter();
                p.ParameterName = "@" + column_name;
                p.SourceColumn = column_name;
                cmd.Parameters.Add(p);
            }

            // удаляем последнюю запятую в тексте команды
            insertion_columns = insertion_columns.Remove(insertion_columns.Length - 2) + ")";
            insertion_parameters = insertion_parameters.Remove(insertion_parameters.Length - 2) + ")";
            
            // окончательно выставляем текст команды обновления
            cmd.CommandText = Insert_Text + insertion_columns + insertion_parameters;

            // передаем ее адаптеру
            adapter.InsertCommand = cmd;

            // и, наконец-то, пытаемся обновить таблицу
            adapter.Update(tmp_ds, table_name);

            Console.WriteLine("Inserted data to table " + table_name + " successfully");
        }

        void IServer.DeleteFromTable(String table_name, String content)
        {
            // выводим в консоль имя таблицы, которую будем обновлять
            Console.WriteLine("REQUEST FROM CLIENT: Delete from table " + table_name);

            System.IO.StringReader content_xml = new System.IO.StringReader(content);

            DataSet tmp_ds = new DataSet("ds_" + table_name);
            tmp_ds.ReadXml(content_xml, XmlReadMode.Auto);

            // изменяем RowState строки в таблице на Deleted
            tmp_ds.AcceptChanges();
            tmp_ds.Tables[table_name].Rows[0].Delete();

            String query = "SELECT * FROM " + table_name;

            // Connect to the database and run the query.        
            SqlDataAdapter adapter = new SqlDataAdapter(query, Connection);

            // Create a command builder to generate SQL update, insert, and
            // delete commands based on selectCommand. These are used to
            // update the database.
            SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter);

            String Delete_Text = @"DELETE FROM " + table_name + " WHERE [id] = @id";
            SqlCommand cmd = new SqlCommand(Delete_Text, Connection);

            // первичный ключ
            SqlParameter parameter = cmd.Parameters.Add("@id", SqlDbType.VarChar, 50, "id");
            parameter.SourceVersion = DataRowVersion.Original;

            adapter.DeleteCommand = cmd;

            adapter.Update(tmp_ds, table_name);

            Console.WriteLine("Deleted data from table " + table_name);
        }

        void IServer.Disconnect()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
